import 'package:flutter/material.dart';
import 'package:multi_clickable_shape_widget/widget/LineBean.dart';
import 'package:multi_clickable_shape_widget/widget/ShapeController.dart';

typedef OnShapeTap = void Function(List<PathBean>);

class MultiClickableShapeWidget extends StatefulWidget {
  final MultiClickableShapeController controller;
  final OnShapeTap? onShapeTap;
  final CustomPainter? painter;
  const MultiClickableShapeWidget({
    super.key,
    required this.controller,
    this.onShapeTap,
    this.painter,
  });
  @override
  State<StatefulWidget> createState() => MultiClickableShapeWidgetState();
}

class MultiClickableShapeWidgetState extends State<MultiClickableShapeWidget> {
  var lineIndex = -1;
  var pathIndex = -1;

  bool dragDot = false;

  void onPanStart(DragStartDetails details) {
    if (widget.controller.isEdit) {
      var x = details.localPosition.dx;
      var y = details.localPosition.dy;
      var handle = widget.controller.radius * 2;
      for (var j = widget.controller.lines.length - 1; j >= 0; j--) {
        var m = widget.controller.lines[j];
        for (var i = 0; i < m.line.length; i++) {
          var line = m.line[i];
          if (x > line.dx - handle &&
              x < line.dx + handle &&
              y > line.dy - handle &&
              y < line.dy + handle) {
            lineIndex = i;
            pathIndex = j;
            dragDot = true;
            break;
          }
        }
        if (lineIndex == -1 && pathIndex == -1) {
          if (m.contain(details.localPosition)) {
            dragDot = false;
            pathIndex = j;
            widget.controller.selectPathIndex = j;
            break;
          }
        }
      }
    } else {
      List<PathBean> lines = [];
      for (var m in widget.controller.lines) {
        Path path = Path();
        for (var j = 0; j < m.line.length; j++) {
          var line = m.line[j];
          if (j == 0) {
            path.moveTo(line.dx, line.dy);
          } else {
            path.lineTo(line.dx, line.dy);
          }
        }
        path.close();
        if (path.contains(details.localPosition)) {
          lines.add(m);
        }
      }

      widget.onShapeTap?.call(lines);
    }
  }

  void onPanUpdate(DragUpdateDetails details) {
    if (widget.controller.isEdit) {
      if (dragDot) {
        if (lineIndex == -1 || pathIndex == -1) return;
        widget.controller.changeLine(
          pathIndex,
          lineIndex,
          Offset(details.localPosition.dx, details.localPosition.dy),
        );
        widget.controller.setSelectDot(lineIndex);
      } else {
        if (pathIndex == -1) return;
        widget.controller.changeAllLine(pathIndex, details);
      }
    } else {}
  }

  void onPanEnd(DragEndDetails details) {
    pathIndex = -1;
    lineIndex = -1;
  }

  @override
  void initState() {
    super.initState();
    widget.controller.addListener(() {
      setState(() {});
    });
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        color: widget.controller.bgColor,
        width: widget.controller.width,
        height: widget.controller.height,
        child: Stack(
          children: [
            GestureDetector(
              onPanStart: onPanStart,
              onPanUpdate: onPanUpdate,
              onPanEnd: onPanEnd,
              child: CustomPaint(
                painter: _ShapePainter(widget.controller),
                child: SizedBox.expand(),
              ),
            ),
            widget.painter == null
                ? Container()
                : Positioned.fill(
                    child: CustomPaint(
                      painter: widget.painter,
                      child: SizedBox.expand(),
                    ),
                  ),
          ],
        ),
      ),
    );
  }
}

class _ShapePainter extends CustomPainter {
  final MultiClickableShapeController controller;

  _ShapePainter(this.controller) : super(repaint: controller);
  @override
  void paint(Canvas canvas, Size size) {
    canvas.save();
    canvas.clipRect(Rect.fromLTWH(0, 0, size.width, size.height));
    Paint paint = Paint();
    paint.strokeCap = StrokeCap.round;
    paint.strokeWidth = 1;
    Paint strokePaint = Paint()
      ..color = Colors.red
      ..style = PaintingStyle.stroke
      ..strokeWidth = 2;
    for (var i = 0; i < controller.lines.length; i++) {
      var l = controller.lines[i];
      paint.color = l.color;
      Path path = Path();
      for (var j = 0; j < l.line.length; j++) {
        var line = l.line[j];
        if (j == 0) {
          path.moveTo(line.dx, line.dy);
        } else {
          path.lineTo(line.dx, line.dy);
        }
      }
      path.close();
      canvas.drawPath(path, paint);
      if (controller.selectPathIndex == i && controller.isEdit) {
        canvas.drawPath(path, strokePaint);
      }
      paint.color = Colors.blue;
      for (var j = 0; j < l.line.length; j++) {
        var line = l.line[j];
        if (controller.selectPathIndex == i &&
            controller.selectDot == j &&
            controller.isEdit) {
          canvas.drawCircle(line, controller.radius, paint);
        }
      }
    }
    canvas.restore();
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
